using System.Threading.Tasks;
using Microsoft.Practices.Unity;
using UnityDemo.InstanceManagerCode.LifeTimeModels;
using UnityDemo.LoggingUtility;
using UnityDemo.Models;

namespace UnityDemo.InstanceManagerCode.LifetimeTypes
{
    internal class PerThreadLifetimeManagerDemo : ISample
    {
        //  PerThreadLifetimeManager. Unity returns, on a per-thread basis, the same instance of the registered type or
        //object each time you call the Resolve or ResolveAll method or when the dependency mechanism injects instances
        //into other classes. This lifetime manager effectively implements a singleton behavior for objects on a per-thread
        //basis. PerThreadLifetimeManager returns different objects from the container for each thread.
        //The behavior is as follows: If you used the RegisterType method to register a type, Unity creates a new
        //instance of the registered type the first time the type is resolved in a specified thread, either to answer a
        //call to the Resolve or ResolveAll methods for the registered type or to fulfill a dependency while resolving a
        //different type. Subsequent resolutions on the same thread return the same instance.
        //Using the RegisterInstance method to register an existing object results in the same behavior as if you
        //just registered the lifetime container with RegisterType. Therefore, it is recommended that you do not use
        //the RegisterInstance method to register an existing object when using the PerThreadLifetimeManager.
        //PerThreadLifetimeManager returns the object desired or permits the container to create a new instance
        //if no such object is currently stored for the current thread. A new instance is also created if called
        //on a different thread than the one that set the value. This lifetime manager does not dispose the instances
        //it holds.

        public PerThreadLifetimeManagerDemo()
        {
            var container = new UnityContainer();

            container.RegisterType<SingletonInstance>(new ContainerControlledLifetimeManager());
            container.RegisterType<PerInstance>();
            container.RegisterType<ExternalInstanceLifetime>(new ExternallyControlledLifetimeManager());
            container.RegisterType<PerThredInstance>(new PerThreadLifetimeManager());
            container.RegisterType<HierarchicalLifetimeInstance>(new HierarchicalLifetimeManager());

            var threadInstance1 = container.Resolve<PerThredInstance>();
            threadInstance1.PrintHashCode();
            var threadInstance2 = container.Resolve<PerThredInstance>();
            threadInstance2.PrintHashCode();

            Task.Factory.StartNew(() => ThreadCalledMethod(1));
            Task.Factory.StartNew(() => ThreadCalledMethod(2));
        }

        private void ThreadCalledMethod(int threadNumber)
        {
            var container = new UnityContainer();

            LogerInstance.Logger.Info("Current thread number =" + threadNumber);
            var threadInstance1 = container.Resolve<PerThredInstance>();
            threadInstance1.PrintHashCode(threadNumber);
            var threadInstance2 = container.Resolve<PerThredInstance>();
            threadInstance2.PrintHashCode(threadNumber);
        }
    }
}